/*! \file
 * \brief Interface of the myth library.
 *
 * This file serves as a configuration file for all of the sub
 * libraries.
 * \author Ivo Wingelaar
 * \date 2011
 * \version 0.1.0
 * \copyright GNU Lesser General Public License v3
 */

#ifndef __MYTH_HPP_INCLUDED__
#define __MYTH_HPP_INCLUDED__

//! The major version number.
#define MYTH_SDK_VERSION_MAJOR 0
//! The minor version number, in the interval [0, 9].
#define MYTH_SDK_VERSION_MINOR 1
//! The version number, in the interval [0, 9].
#define MYTH_SDK_VERSION_VERSION 0
//! The complete version number.
#define MYTH_SDK_VERSION MYTH_SDK_VERSION_MAJOR * 100 + MYTH_SDK_VERSION_MINOR * 10 + MYTH_SDK_VERSION_VERSION

#if (defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64))
#define _MYTH_WINDOWS_
#else
#define _MYTH_LINUX_
#endif

#ifdef _MYTH_WINDOWS_
#ifdef _STDCALL_SUPPORTED
#define _MYTH_CALL_CONV_ __stdcall
#else
#define _MYTH_CALL_CONV_ __cdecl
#endif // _STDCALL_SUPPORTED
#endif // _MYTH_WINDOWS_

#ifdef _MYTH_LINUX_
#define _MYTH_CALL_CONV_
#endif // _MYTH_LINUX_

#include <memory.h>
#include <new>
#include <string>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>

// for byteswapping
#if defined(_MYTH_WINDOWS_) && defined(_MSC_VER) && (_MSC_VER > 1298)
#include <stdlib.h>
#define bswap_16(X) _byteswap_ushort(X)
#define bswap_32(X) _byteswap_ulong(X)
#elif defined(_MYTH_WINDOWS_)

#define bswap_16(X) ((((X)&0xFF) << 8) | (((X)&0xFF00) >> 8))

#define bswap_32(X) ((((X)&0x000000FF)<<24) | (((X)&0xFF000000) >> 24) | (((X)&0x0000FF00) << 8) | (((X) &0x00FF0000) >> 8))

#define bswap_64(X) (((X)<<56) | (((X)<<40)&0xFF000000000000ULL) | (((X)<<24)&0xFF0000000000ULL) | (((X)<<8)&0xFF00000000ULL) | (((X)>>8)&0xFF000000) | (((X)>>24)&0xFF0000) | (((X)>>40)&0xFF00) | ((X)>>56))

#elif defined(_MYTH_OSX_)
#include <libkern/OSByteOrder.h>
#define bswap_16(X) OSReadSwapInt16(&X,0)
#define bswap_32(X) OSReadSwapInt32(&X,0)
#elif defined(_MYTH_LINUX_)
#include <byteswap.h>
#endif

//! The main namespace of the myth library.
namespace Myth
{

//! Returns an 8 bit value that is unchanged, to prevent accidental swapping.
/*!
 * \return An 8 bit value that is unchanged, to prevent accidental swapping.
 * \param[in] x An unsigned 8 bit value.
 */
inline uint8_t byteswap(uint8_t x)
{
    return x;
}

//! Returns an 8 bit value that is unchanged, to prevent accidental swapping.
/*!
 * \return An 8 bit value that is unchanged, to prevent accidental swapping.
 * \param[in] x A signed 8 bit value.
 */
inline int8_t byteswap(int8_t x)
{
    return x;
}

//! Returns an char value that is unchanged, to prevent accidental swapping.
/*!
 * \return A char value that is unchanged, to prevent accidental swapping.
 * \param[in] x A char value.
 */
inline char byteswap(char x)
{
    return x;
}

//! Returns a value with all bytes in the 16 bit argument swapped.
/*!
 * \return An unsigned 16 bit value with its bytes swapped.
 * \param[in] x An unsigned 16 bit value.
 */
inline uint16_t byteswap(uint16_t x)
{
    return bswap_16(x);
}

//! Returns a value with all bytes in the 16 bit argument swapped.
/*!
 * \return A signed 16 bit value with its bytes swapped.
 * \param[in] x A signed 16 bit value.
 */
inline int16_t byteswap(int16_t x)
{
    return bswap_16(x);
}

//! Returns a value with all bytes in the 32 bit argument swapped.
/*!
 * \return An unsigned 32 bit value with its bytes swapped.
 * \param[in] x An unsigned 32 bit value.
 */
inline uint32_t byteswap(uint32_t x)
{
    return bswap_32(x);
}

//! Returns a value with all bytes in the 32 bit argument swapped.
/*!
 * \return A signed 32 bit value with its bytes swapped.
 * \param[in] x A signed 32 bit value.
 */
inline int32_t byteswap(int32_t x)
{
    return bswap_32(x);
}

//! Returns a value with all bytes in the 64 bit argument swapped.
/*!
 * \return An unsigned 64 bit value with its bytes swapped.
 * \param[in] x An unsigned 64 bit value.
 */
inline uint64_t byteswap(uint64_t x)
{
    return bswap_64(x);
}

//! Returns a value with all bytes in the 64 bit argument swapped.
/*!
 * \return A signed 64 bit value with its bytes swapped.
 * \param[in] x A signed 64 bit value.
 */
inline int64_t byteswap(int64_t x)
{
    return bswap_64(x);
}

//! Returns a value with all bytes in the 32 bit argument swapped.
/*!
 * \return A 32 bit floating point value with its bytes swapped.
 * \param[in] x A 32 bit floating point value.
 */
inline float byteswap(float x)
{
    uint32_t tmp = bswap_32(*((uint32_t*)(&x)));
    return *((float*)(&tmp));
}

//! Returns a value with all bytes in the 64 bit argument swapped.
/*!
 * \return A 64 bit floating point value with its bytes swapped.
 * \param[in] x A 64 bit floating point value.
 */
inline double byteswap(double x)
{
    uint64_t tmp = bswap_64(*((uint64_t*)(&x)));
    return *((double*)(&tmp));
}

//! A class that does reference counting on a derived classes.
class ReferenceCounter
{
public:
    //! Default constructor.
    /*!
     * On creation, the counter is to 1 and it will be incremented when
     * other objects start using it, and decremented when they won't need
     * it anymore. When the counter hits 0 the objected is deleted.
     */
    ReferenceCounter() :
        mReferenceCounter(1)
    {
        //
    }

    //! Virtual destructor.
    virtual ~ReferenceCounter()
    {
        //
    }

    //! Increase the reference counter by 1.
    void increment_counter(void) const
    {
        mReferenceCounter++;
    }

    //! Decrease the reference counter by 1 and delete object if not used anymore.
    /*!
     * \return True if the object was deleted, false otherwise.
     */
    bool decrement_counter(void) const
    {
        mReferenceCounter--;

        if(mReferenceCounter == 0)
        {
            delete this;
            return true;
        }

        return false;
    }

    //! Return the current value of the reference counter.
    /*!
     * \return The current value of the reference counter.
     */
    int32_t get_counter(void) const
    {
        return mReferenceCounter;
    }

private:
    //! The reference counter.
    mutable int32_t mReferenceCounter;
};


static const char hexTable[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

inline void binary_to_hex( uint8_t* data, char* hex, size_t dataSize)
{
    for(size_t a = 0; a < dataSize; a++)
        ((uint16_t*)hex)[a] = (hexTable[(data[a] & 0xf0) >> 4]) | (hexTable[data[a] & 0xf] << 8);
}

inline uint8_t string_to_uint8(const std::string& str)
{
    return atoi(str.c_str());
}

inline uint16_t string_to_uint16(const std::string& str)
{
    return atoi(str.c_str());
}

inline uint32_t string_to_uint32(const std::string& str)
{
    return atoi(str.c_str());
}

inline uint64_t string_to_uint64(const std::string& str)
{
    return atoll(str.c_str());
}

inline int8_t string_to_int8(const std::string& str)
{
    return atoi(str.c_str());
}

inline int16_t string_to_int16(const std::string& str)
{
    return atoi(str.c_str());
}

inline int32_t string_to_int32(const std::string& str)
{
    return atoi(str.c_str());
}

inline int64_t string_to_int64(const std::string& str)
{
    return atoll(str.c_str());
}

inline float string_to_float(const std::string& str)
{
    return atof(str.c_str());
}

inline double string_to_double(const std::string& str)
{
    return atof(str.c_str());
}

inline std::string uint8_to_string(uint8_t x)
{
    char v[4];
    snprintf(v, 4, "%u", x);
    return std::string(v);
}

inline std::string uint16_to_string(uint16_t x)
{
    char v[6];
    snprintf(v, 6, "%u", x);
    return std::string(v);
}

inline std::string uint32_to_string(uint32_t x)
{
    char v[11];
    snprintf(v, 11, "%u", x);
    return std::string(v);
}

inline std::string uint64_to_string(uint64_t x)
{
    char v[21];
    snprintf(v, 21, "%lu", x);
    return std::string(v);
}

inline std::string int8_to_string(int8_t x)
{
    char v[5];
    snprintf(v, 5, "%d", x);
    return std::string(v);
}

inline std::string int16_to_string(int16_t x)
{
    char v[7];
    snprintf(v, 7, "%d", x);
    return std::string(v);
}

inline std::string int32_to_string(int32_t x)
{
    char v[12];
    snprintf(v, 12, "%d", x);
    return std::string(v);
}

inline std::string int64_to_string(int64_t x)
{
    char v[21];
    snprintf(v, 21, "%ld", x);
    return std::string(v);
}

inline std::string float_to_string(float x)
{
    char v[255];
    snprintf(v, 255, "%.20f", x);
    return std::string(v);
}

inline std::string double_to_string(double x)
{
    char v[255];
    snprintf(v, 255, "%.20f", x);
    return std::string(v);
}

} // namespace Myth

#endif // __MYTH_HPP_INCLUDED__

